1 /*
2 * Copyright (C) 2009 The Guava Authors
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package com.google.common.util.concurrent;
18
19 import com.google.common.annotations.Beta;
20
21 import java.util.concurrent.Executor;
22 import java.util.concurrent.TimeUnit;
23 import java.util.concurrent.TimeoutException;
24
25 /**
26 * An object with an operational state, plus asynchronous {@link #startAsync()} and
27 * {@link #stopAsync()} lifecycle methods to transition between states. Example services include
28 * webservers, RPC servers and timers.
29 *
30 * <p>The normal lifecycle of a service is:
31 * <ul>
32 * <li>{@linkplain State#NEW NEW} ->
33 * <li>{@linkplain State#STARTING STARTING} ->
34 * <li>{@linkplain State#RUNNING RUNNING} ->
35 * <li>{@linkplain State#STOPPING STOPPING} ->
36 * <li>{@linkplain State#TERMINATED TERMINATED}
37 * </ul>
38 *
39 * <p>There are deviations from this if there are failures or if {@link Service#stopAsync} is called
40 * before the {@link Service} reaches the {@linkplain State#RUNNING RUNNING} state. The set of legal
41 * transitions form a <a href="http://en.wikipedia.org/wiki/Directed_acyclic_graph">DAG</a>,
42 * therefore every method of the listener will be called at most once. N.B. The {@link State#FAILED}
43 * and {@link State#TERMINATED} states are terminal states, once a service enters either of these
44 * states it cannot ever leave them.
45 *
46 * <p>Implementors of this interface are strongly encouraged to extend one of the abstract classes
47 * in this package which implement this interface and make the threading and state management
48 * easier.
49 *
50 * @author Jesse Wilson
51 * @author Luke Sandberg
52 * @since 9.0 (in 1.0 as {@code com.google.common.base.Service})
53 */
54 @Beta
55 public interface Service {
56 /**
57 * If the service state is {@link State#NEW}, this initiates service startup and returns
58 * immediately. A stopped service may not be restarted.
59 *
60 * @return this
61 * @throws IllegalStateException if the service is not {@link State#NEW}
62 *
63 * @since 15.0
64 */
65 Service startAsync();
66
67 /**
68 * Returns {@code true} if this service is {@linkplain State#RUNNING running}.
69 */
70 boolean isRunning();
71
72 /**
73 * Returns the lifecycle state of the service.
74 */
75 State state();
76
77 /**
78 * If the service is {@linkplain State#STARTING starting} or {@linkplain State#RUNNING running},
79 * this initiates service shutdown and returns immediately. If the service is
80 * {@linkplain State#NEW new}, it is {@linkplain State#TERMINATED terminated} without having been
81 * started nor stopped. If the service has already been stopped, this method returns immediately
82 * without taking action.
83 *
84 * @return this
85 * @since 15.0
86 */
87 Service stopAsync();
88
89 /**
90 * Waits for the {@link Service} to reach the {@linkplain State#RUNNING running state}.
91 *
92 * @throws IllegalStateException if the service reaches a state from which it is not possible to
93 * enter the {@link State#RUNNING} state. e.g. if the {@code state} is
94 * {@code State#TERMINATED} when this method is called then this will throw an
95 * IllegalStateException.
96 *
97 * @since 15.0
98 */
99 void awaitRunning();
100
101 /**
102 * Waits for the {@link Service} to reach the {@linkplain State#RUNNING running state} for no
103 * more than the given time.
104 *
105 * @param timeout the maximum time to wait
106 * @param unit the time unit of the timeout argument
107 * @throws TimeoutException if the service has not reached the given state within the deadline
108 * @throws IllegalStateException if the service reaches a state from which it is not possible to
109 * enter the {@link State#RUNNING RUNNING} state. e.g. if the {@code state} is
110 * {@code State#TERMINATED} when this method is called then this will throw an
111 * IllegalStateException.
112 *
113 * @since 15.0
114 */
115 void awaitRunning(long timeout, TimeUnit unit) throws TimeoutException;
116
117 /**
118 * Waits for the {@link Service} to reach the {@linkplain State#TERMINATED terminated state}.
119 *
120 * @throws IllegalStateException if the service {@linkplain State#FAILED fails}.
121 *
122 * @since 15.0
123 */
124 void awaitTerminated();
125
126 /**
127 * Waits for the {@link Service} to reach a terminal state (either
128 * {@link Service.State#TERMINATED terminated} or {@link Service.State#FAILED failed}) for no
129 * more than the given time.
130 *
131 * @param timeout the maximum time to wait
132 * @param unit the time unit of the timeout argument
133 * @throws TimeoutException if the service has not reached the given state within the deadline
134 * @throws IllegalStateException if the service {@linkplain State#FAILED fails}.
135 * @since 15.0
136 */
137 void awaitTerminated(long timeout, TimeUnit unit) throws TimeoutException;
138
139 /**
140 * Returns the {@link Throwable} that caused this service to fail.
141 *
142 * @throws IllegalStateException if this service's state isn't {@linkplain State#FAILED FAILED}.
143 *
144 * @since 14.0
145 */
146 Throwable failureCause();
147
148 /**
149 * Registers a {@link Listener} to be {@linkplain Executor#execute executed} on the given
150 * executor. The listener will have the corresponding transition method called whenever the
151 * service changes state. The listener will not have previous state changes replayed, so it is
152 * suggested that listeners are added before the service starts.
153 *
154 * <p>{@code addListener} guarantees execution ordering across calls to a given listener but not
155 * across calls to multiple listeners. Specifically, a given listener will have its callbacks
156 * invoked in the same order as the underlying service enters those states. Additionally, at most
157 * one of the listener's callbacks will execute at once. However, multiple listeners' callbacks
158 * may execute concurrently, and listeners may execute in an order different from the one in which
159 * they were registered.
160 *
161 * <p>RuntimeExceptions thrown by a listener will be caught and logged. Any exception thrown
162 * during {@code Executor.execute} (e.g., a {@code RejectedExecutionException}) will be caught and
163 * logged.
164 *
165 * @param listener the listener to run when the service changes state is complete
166 * @param executor the executor in which the listeners callback methods will be run. For fast,
167 * lightweight listeners that would be safe to execute in any thread, consider
168 * {@link MoreExecutors#directExecutor}.
169 * @since 13.0
170 */
171 void addListener(Listener listener, Executor executor);
172
173 /**
174 * The lifecycle states of a service.
175 *
176 * <p>The ordering of the {@link State} enum is defined such that if there is a state transition
177 * from {@code A -> B} then {@code A.compareTo(B} < 0}. N.B. The converse is not true, i.e. if
178 * {@code A.compareTo(B} < 0} then there is <b>not</b> guaranteed to be a valid state transition
179 * {@code A -> B}.
180 *
181 * @since 9.0 (in 1.0 as {@code com.google.common.base.Service.State})
182 */
183 @Beta // should come out of Beta when Service does
184 enum State {
185 /**
186 * A service in this state is inactive. It does minimal work and consumes
187 * minimal resources.
188 */
189 NEW {
190 @Override boolean isTerminal() {
191 return false;
192 }
193 },
194
195 /**
196 * A service in this state is transitioning to {@link #RUNNING}.
197 */
198 STARTING {
199 @Override boolean isTerminal() {
200 return false;
201 }
202 },
203
204 /**
205 * A service in this state is operational.
206 */
207 RUNNING {
208 @Override boolean isTerminal() {
209 return false;
210 }
211 },
212
213 /**
214 * A service in this state is transitioning to {@link #TERMINATED}.
215 */
216 STOPPING {
217 @Override boolean isTerminal() {
218 return false;
219 }
220 },
221
222 /**
223 * A service in this state has completed execution normally. It does minimal work and consumes
224 * minimal resources.
225 */
226 TERMINATED {
227 @Override boolean isTerminal() {
228 return true;
229 }
230 },
231
232 /**
233 * A service in this state has encountered a problem and may not be operational. It cannot be
234 * started nor stopped.
235 */
236 FAILED {
237 @Override boolean isTerminal() {
238 return true;
239 }
240 };
241
242 /** Returns true if this state is terminal. */
243 abstract boolean isTerminal();
244 }
245
246 /**
247 * A listener for the various state changes that a {@link Service} goes through in its lifecycle.
248 *
249 * <p>All methods are no-ops by default, implementors should override the ones they care about.
250 *
251 * @author Luke Sandberg
252 * @since 15.0 (present as an interface in 13.0)
253 */
254 @Beta // should come out of Beta when Service does
255 abstract class Listener {
256 /**
257 * Called when the service transitions from {@linkplain State#NEW NEW} to
258 * {@linkplain State#STARTING STARTING}. This occurs when {@link Service#startAsync} is called
259 * the first time.
260 */
261 public void starting() {}
262
263 /**
264 * Called when the service transitions from {@linkplain State#STARTING STARTING} to
265 * {@linkplain State#RUNNING RUNNING}. This occurs when a service has successfully started.
266 */
267 public void running() {}
268
269 /**
270 * Called when the service transitions to the {@linkplain State#STOPPING STOPPING} state. The
271 * only valid values for {@code from} are {@linkplain State#STARTING STARTING} or
272 * {@linkplain State#RUNNING RUNNING}. This occurs when {@link Service#stopAsync} is called.
273 *
274 * @param from The previous state that is being transitioned from.
275 */
276 public void stopping(State from) {}
277
278 /**
279 * Called when the service transitions to the {@linkplain State#TERMINATED TERMINATED} state.
280 * The {@linkplain State#TERMINATED TERMINATED} state is a terminal state in the transition
281 * diagram. Therefore, if this method is called, no other methods will be called on the
282 * {@link Listener}.
283 *
284 * @param from The previous state that is being transitioned from. The only valid values for
285 * this are {@linkplain State#NEW NEW}, {@linkplain State#RUNNING RUNNING} or
286 * {@linkplain State#STOPPING STOPPING}.
287 */
288 public void terminated(State from) {}
289
290 /**
291 * Called when the service transitions to the {@linkplain State#FAILED FAILED} state. The
292 * {@linkplain State#FAILED FAILED} state is a terminal state in the transition diagram.
293 * Therefore, if this method is called, no other methods will be called on the {@link Listener}.
294 *
295 * @param from The previous state that is being transitioned from. Failure can occur in any
296 * state with the exception of {@linkplain State#NEW NEW} or
297 * {@linkplain State#TERMINATED TERMINATED}.
298 * @param failure The exception that caused the failure.
299 */
300 public void failed(State from, Throwable failure) {}
301 }
302 }